layout.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import { ConfigType } from "@/api/config";
  2. import Dialogs from "@/components/Dialog";
  3. // import AutoShowDialog from "@/dialog/auto";
  4. import Loading2 from "@/components/Loading2";
  5. import { routing } from "@/i18n/routing";
  6. import { server } from "@/utils/server";
  7. import "animate.css";
  8. import clsx from "clsx";
  9. import { Viewport } from "next";
  10. import { NextIntlClientProvider } from "next-intl";
  11. import { getMessages } from "next-intl/server";
  12. import { Inter as FontSans } from "next/font/google";
  13. import { notFound } from "next/navigation";
  14. import { ReactNode, Suspense } from "react";
  15. import "../editor.scss";
  16. import "../globals.scss";
  17. import { Providers } from "./providers";
  18. // 加载字体
  19. const fontSans = FontSans({
  20. subsets: ["latin"],
  21. variable: "--font-sans",
  22. });
  23. export const viewport: Viewport = {};
  24. interface Og {
  25. description: string;
  26. keywords: string;
  27. title: string;
  28. url: string;
  29. address: string;
  30. }
  31. interface System extends ConfigType {
  32. og: Og;
  33. }
  34. const getSystemReq = () => {
  35. return server.request<System>({
  36. url: "/v1/api/front/system/configs",
  37. method: "POST",
  38. });
  39. };
  40. export const generateMetadata = async () => {
  41. const { data } = await getSystemReq();
  42. return {
  43. title: {
  44. template: "%s | 8G.game",
  45. default: "8G.game",
  46. },
  47. keywords: ["8G.game"],
  48. description: "The home of over 30 million players",
  49. appleWebApp: {
  50. statusBarStyle: "black",
  51. },
  52. formatDetection: {
  53. email: false,
  54. address: false,
  55. telephone: false,
  56. },
  57. referrer: "no-referrer",
  58. other: {
  59. viewport: [
  60. "width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0," +
  61. " viewport-fit=cover ",
  62. ],
  63. },
  64. openGraph: {
  65. title: data?.og?.title,
  66. description: data?.og?.description,
  67. image: data?.og?.url,
  68. url: data?.og?.address,
  69. },
  70. twitter: {
  71. card: data?.og?.address,
  72. title: data?.og?.title,
  73. description: data?.og?.description,
  74. image: data?.og?.url,
  75. },
  76. };
  77. };
  78. export default async function LocaleLayout({
  79. children,
  80. params: { locale },
  81. }: {
  82. children: ReactNode;
  83. params: { locale: string };
  84. }) {
  85. if (!routing.locales.includes(locale as any)) {
  86. notFound();
  87. }
  88. const messages = await getMessages();
  89. return (
  90. <html lang={locale} suppressHydrationWarning data-renterid={process.env.RENTER_ID}>
  91. <head>
  92. <script defer={true} src={"/iconfont.js"} />
  93. </head>
  94. <body className={clsx("font-sans", fontSans.variable)}>
  95. <NextIntlClientProvider messages={messages}>
  96. <Providers themeProps={{ attribute: "class" }}>
  97. {children}
  98. <Suspense>
  99. <Dialogs></Dialogs>
  100. </Suspense>
  101. </Providers>
  102. </NextIntlClientProvider>
  103. <div
  104. id="globalMask"
  105. style={{
  106. position: "fixed",
  107. zIndex: 100,
  108. background: "rgba(0,0,0,.8)",
  109. display: "none",
  110. left: 0,
  111. top: 0,
  112. right: 0,
  113. bottom: 0,
  114. alignItems: "center",
  115. justifyContent: "center",
  116. }}
  117. >
  118. <Loading2 width={10}></Loading2>
  119. </div>
  120. </body>
  121. </html>
  122. );
  123. }